package com.ms.zuul.filter;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.monitor.log.biz.core.BizLogData;
import com.monitor.log.biz.core.BizLogUtil;
import com.ms.zuul.filter.core.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.system.auth.AuthUtil;
import com.system.auth.model.AuthClient;
import com.system.comm.constants.StringCons;
import com.system.comm.utils.FrameHttpRequestUtil;
import com.system.comm.utils.FrameJsonUtil;
import com.system.comm.utils.FrameMapUtil;
import com.system.comm.utils.FrameStringUtil;
import com.system.handle.model.ResponseCode;
import com.system.handle.model.ResponseFrame;

public class AccessPreFilter extends ZuulFilter {

	private static Logger LOGGER = LoggerFactory.getLogger(AccessPreFilter.class);

	@Override
	public String filterType() {
		//pre、post和error。分别代表前置过滤，后置过滤和异常过滤
		return "pre";
	}
	@Override
	public int filterOrder() {
		//过滤器顺序
		return 0;
	}
	@Override
	public boolean shouldFilter() {
		//代表这个过滤器是否生效
		return true;
	}
	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();

		String clientId = request.getParameter("clientId");
		String sign = request.getParameter("sign");
		String time = request.getParameter("time");
		String contentType = request.getContentType();
		if (FrameStringUtil.isNotEmpty(contentType) && contentType.contains(StringCons.MULTIPART_FORM_DATA)) {
			// 获取到multipart/form-data类型的参数
			HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) request;
			clientId = httpServletRequestWrapper.getRequest().getParameter("clientId");
			sign = httpServletRequestWrapper.getRequest().getParameter("sign");
			time = httpServletRequestWrapper.getRequest().getParameter("time");
		}

		String uri = request.getRequestURI();

		if(FrameStringUtil.isEmpty(clientId)) {
			//处理requestBody传参的情况
			Map<String, Object> requestMap = FrameHttpRequestUtil.getReqBodyParams(request);
			clientId = FrameMapUtil.getString(requestMap, "clientId");
			sign = FrameMapUtil.getString(requestMap, "sign");
			time = FrameMapUtil.getString(requestMap, "time");
			/*try {
				InputStream in = (InputStream) ctx.get("requestEntity");
				if (in == null) {
					in = ctx.getRequest().getInputStream();
				}
				String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
				Map<String, Object> map = FrameJsonUtil.toMap(body);
				clientId = FrameMapUtil.getString(map, "clientId");
				sign = FrameMapUtil.getString(map, "sign");
				time = FrameMapUtil.getString(map, "time");

				Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
				if (requestQueryParams == null) {
					requestQueryParams = new HashMap<>();
				}
				Iterator<Entry<String, Object>> entryKeyIterator = map.entrySet().iterator();
				while (entryKeyIterator.hasNext()) {
					Entry<String, Object> e = entryKeyIterator.next();
					String value = e.getValue() != null ? e.getValue().toString(): null;
					//将要新增的参数添加进去,被调用的微服务可以直接 去取,就想普通的一样,框架会直接注入进去
					ArrayList<String> arrayList = new ArrayList<>();
					arrayList.add(value);
					requestQueryParams.put(e.getKey(), arrayList);
				}
				//将参数设置到请求参数里面
				ctx.setRequestQueryParams(requestQueryParams);

			} catch (IOException e) {
				e.printStackTrace();
			}*/
		}

		LOGGER.info("{ clientId:" + clientId + ", time:" + time + ", sign:" + sign + " } 请求地址: " + uri);
		AuthClient client = AuthUtil.get(clientId);
		if(client == null) {
			LOGGER.error("非法请求(abnormal signature): { clientId:" + clientId + ", time:" + time + ", sign:" + sign + " } 请求地址: " + request.getRequestURI());
			ResponseFrame frame = new ResponseFrame();
			frame.setCode(ResponseCode.ABNORMAL_SIGNATURE.getCode());
			frame.setMessage(ResponseCode.ABNORMAL_SIGNATURE.getMessage());
			ctx.getResponse().setContentType("text/html;charset=UTF-8");
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			String responseResult = FrameJsonUtil.toString(frame);
			ctx.setResponseBody(responseResult);
			BizLogUtil.saveLogZuulFilter(request, responseResult);
			return null;
		}
		//处理是否超额访问
		if(client.getReqMaxSecond() != null && client.getReqMaxSecond().longValue() > 0) {
			RateLimiter rateLimiter = new RateLimiter(clientId);
			if(!rateLimiter.acquireSecond(client.getReqMaxSecond().longValue())) {
				LOGGER.error("超过每秒钟最大请求数: " + client.getReqMaxSecond() + "次");
				ResponseFrame frame = new ResponseFrame();
				frame.setCode(ResponseCode.REQ_MAX_SECOND.getCode());
				frame.setMessage(ResponseCode.REQ_MAX_SECOND.getMessage() + ": " + client.getReqMaxSecond() + "次");
				ctx.getResponse().setContentType("text/html;charset=UTF-8");
				ctx.setSendZuulResponse(false);
				ctx.setResponseStatusCode(401);
				String responseResult = FrameJsonUtil.toString(frame);
				ctx.setResponseBody(responseResult);
				BizLogUtil.saveLogZuulFilter(request, responseResult);
				return null;
			}
		}
		if(client.getReqMaxHour() != null && client.getReqMaxHour().longValue() > 0) {
			RateLimiter rateLimiter = new RateLimiter(clientId);
			if(!rateLimiter.acquireHour(client.getReqMaxHour().longValue())) {
				LOGGER.error("超过每小时最大请求数: " + client.getReqMaxHour() + "次");
				ResponseFrame frame = new ResponseFrame();
				frame.setCode(ResponseCode.REQ_MAX_HOUR.getCode());
				frame.setMessage(ResponseCode.REQ_MAX_HOUR.getMessage() + ": " + client.getReqMaxHour() + "次");
				ctx.getResponse().setContentType("text/html;charset=UTF-8");
				ctx.setSendZuulResponse(false);
				ctx.setResponseStatusCode(401);
				String responseResult = FrameJsonUtil.toString(frame);
				ctx.setResponseBody(responseResult);
				BizLogUtil.saveLogZuulFilter(request, responseResult);
				return null;
			}
		}
		if(!AuthUtil.authVerify(clientId, time, sign)) {
			LOGGER.error("非法请求(abnormal signature): { clientId:" + clientId + ", time:" + time + ", sign:" + sign + " } 请求地址: " + request.getRequestURI());
			ResponseFrame frame = new ResponseFrame();
			frame.setCode(ResponseCode.ABNORMAL_SIGNATURE.getCode());
			frame.setMessage(ResponseCode.ABNORMAL_SIGNATURE.getMessage());
			ctx.getResponse().setContentType("text/html;charset=UTF-8");
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			String responseResult = FrameJsonUtil.toString(frame);
			ctx.setResponseBody(responseResult);
			BizLogUtil.saveLogZuulFilter(request, responseResult);
			return null;
		}
		//判断请求地址是否通过
		if(!AuthUtil.authVerifyReqUrl(clientId, request.getRequestURI())) {
			LOGGER.error("地址: " + request.getRequestURI() + " 没有权限, clientId[" + clientId + "]");
			ResponseFrame frame = new ResponseFrame();
			frame.setCode(ResponseCode.ABNORMAL_SIGNATURE.getCode());
			frame.setMessage(ResponseCode.ABNORMAL_SIGNATURE.getMessage());
			ctx.getResponse().setContentType("text/html;charset=UTF-8");
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			String responseResult = FrameJsonUtil.toString(frame);
			ctx.setResponseBody(responseResult);
			BizLogUtil.saveLogZuulFilter(request, responseResult);
			return null;
		}
		// 记录Zuul的请求时间
		BizLogData.setZuulReqTime(System.currentTimeMillis());
		//这里return的值没有意义，zuul框架没有使用该返回值
		return null;
	}
}